package cn.hacynn.nd.common.utils;

import cn.hacynn.nd.common.constant.MessageConstant;
import cn.hacynn.nd.common.exception.DownloadException;
import cn.hacynn.nd.common.properties.STSProperties;
import cn.hacynn.nd.pojo.vo.STSVO;
import cn.hutool.core.util.RandomUtil;
import com.aliyuncs.exceptions.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyun.oss.model.*;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
//mport top.retain.nd.dto.STSResp;

import com.aliyun.oss.*;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.net.URL;
import java.util.Date;

import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;


@AllArgsConstructor
@Slf4j
public class OSSUtil {

//    @Value("${OSS.endpoint}")
//    private String endpoint;
//    @Value("${OSS.ram.accessKeyId}")
//    private String accessKeyId;
//    @Value("${OSS.ram.accessKeySecret}")
//    private String accessKeySecret;
//    @Value("${OSS.ram.roleArn}")
//    private String roleArn;
//    @Value("${OSS.region}")
//    private String region;

    // 通过 OssConfiguration 配置类创建了 OSSUtil 对象并赋值
    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String region;
    private String roleArn;

    private STSProperties stsProperties;


    /*
    * 创建oss的buckname桶
    * */
    public String createBucket(Long userId) {
        // 创建OSS客户端实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 创建CreateBucketRequest对象。 该对象包含创建桶所需的信息。
            // 生成一个buckname唯一的桶名称，使用userId和一个10位随机字符串
            String bucketName = userId + "-" + RandomUtil.randomString(10).toLowerCase();
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            //使用OSS客户端的 createBucket 方法来创建桶。
            ossClient.createBucket(createBucketRequest);
            //调用 setCors 方法来设置CORS规则。假设 setCors 是一个已定义的方法，用于配置桶的CORS设置。
            setCors(bucketName);
            return bucketName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            //finally 块中的代码确保了无论 try 块中的代码是否成功执行，都能正确地关闭 ossClient，
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }


    public void setCors(String bucketName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            SetBucketCORSRequest request = new SetBucketCORSRequest(bucketName);
            ArrayList<SetBucketCORSRequest.CORSRule> putCorsRules = new ArrayList<>();

            SetBucketCORSRequest.CORSRule corRule = new SetBucketCORSRequest.CORSRule();

            ArrayList<String> allowedOrigin = new ArrayList<String>();
            // 指定允许跨域请求的来源。
            allowedOrigin.add( "*");

            ArrayList<String> allowedMethod = new ArrayList<String>();
            // 指定允许的跨域请求方法(GET/PUT/DELETE/POST/HEAD)。
            allowedMethod.add("GET");
            allowedMethod.add("PUT");
            allowedMethod.add("DELETE");
            allowedMethod.add("POST");

            ArrayList<String> allowedHeader = new ArrayList<String>();
            // 是否允许预取指令（OPTIONS）中Access-Control-Request-Headers头中指定的Header。
            allowedHeader.add("*");

            ArrayList<String> exposedHeader = new ArrayList<String>();
            // 指定允许用户从应用程序中访问的响应头。
            exposedHeader.add("ETag");
            exposedHeader.add("x-oss-request-id");

            corRule.setAllowedMethods(allowedMethod);
            corRule.setAllowedOrigins(allowedOrigin);
            // AllowedHeaders和ExposeHeaders不支持通配符。
            corRule.setAllowedHeaders(allowedHeader);
            corRule.setExposeHeaders(exposedHeader);
            // 指定浏览器对特定资源的预取（OPTIONS）请求返回结果的缓存时间，单位为秒。
            corRule.setMaxAgeSeconds(100);

            putCorsRules.add(corRule);
            request.setCorsRules(putCorsRules);
            ossClient.setBucketCORS(request);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                // 关闭OSSClient。
                ossClient.shutdown();
            }
        }
    }

    /**
     * 生成STS
     * @return
     */
    public STSVO generateSTS() {
        /*//构建一个阿里云客户端，用于发起请求。
        //构建阿里云客户端时需要设置AccessKey ID和AccessKey Secret。
        DefaultProfile profile = DefaultProfile.getProfile(region, accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);

        //构造请求，设置参数。关于参数含义和设置方法，请参见《API参考》。
        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setRoleArn(roleArn);
        request.setRoleSessionName("tmpRam");
        // 一天过期
        request.setDurationSeconds(43200L);

        //发起请求，并得到响应。
        try {
            STSVO sts = new STSVO();
            AssumeRoleResponse response = client.getAcsResponse(request);
            sts.setCredentials(response.getCredentials());
            log.info("获取STS：" + response.getCredentials().toString());
            return sts;
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (com.aliyuncs.exceptions.ClientException e) {
            log.error("ErrCode:" + e.getErrCode());
            log.error("ErrMsg:" + e.getErrMsg());
            log.error("RequestId:" + e.getRequestId());
        }*/
        return null;
    }

    public STSVO generateStsToken() {
        // STS服务接入点，例如sts.cn-hangzhou.aliyuncs.com。您可以通过公网或者VPC接入STS服务。
        // 从环境变量中获取步骤1生成的RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
        // 从环境变量中获取步骤3生成的RAM角色的RamRoleArn。
        // 自定义角色会话名称，用来区分不同的令牌，例如可填写为SessionTest。
        String roleSessionName = "tmpRam";
        // 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket下的src目录上传文件。
        // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集，即仅允许将文件上传至目标存储空间examplebucket下的src目录。
        // 如果policy为空，则临时访问凭证将获得角色拥有的所有权限。
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:PutObject\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        // 临时访问凭证的有效时间，单位为秒。最小值为900，最大值以当前角色设定的最大会话时间为准。当前角色最大会话时间取值范围为3600秒~43200秒，默认值为3600秒。
        // 在上传大文件或者其他较耗时的使用场景中，建议合理设置临时访问凭证的有效时间，确保在完成目标任务前无需反复调用STS服务以获取临时访问凭证。
        Long durationSeconds = 43200L;
        try {
            // regionId表示RAM的地域ID。以华东1（杭州）地域为例，regionID填写为cn-hangzhou。也可以保留默认值，默认值为空字符串（""）。
            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(region, "Sts", stsProperties.getEndpoint());
            // 添加endpoint。适用于Java SDK 3.12.0以下版本。
            // DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(region, accessKeyId, accessKeySecret);
            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);
            // 适用于Java SDK 3.12.0以下版本。
            //request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            request.setDurationSeconds(durationSeconds);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            return STSVO.builder()
                    .credentials(response.getCredentials())
                    .build();
//            System.out.println("Expiration: " + response.getCredentials().getExpiration());
//            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
//            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
//            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
//            System.out.println("RequestId: " + response.getRequestId());
        } catch (ClientException e) {
            System.out.println("Failed：");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
        }
        return null;
    }



    public boolean isBucketExist(String bucketName) {
        if (StringUtils.isEmpty(bucketName)) {
            return false;
        }
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        boolean exists = ossClient.doesBucketExist(bucketName);
        ossClient.shutdown();
        return exists;
    }


    // ********************上传文件****************


    public boolean createDir(String bucketName, String prefix, String dirName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String targetFilePath = prefix + dirName + "/";
        ObjectMetadata objectMetadata = new ObjectMetadata(); // 创建文件实例
        objectMetadata.setContentType("application/x-directory");  // 设置为目录类型
        objectMetadata.setContentLength(0);  // 设置内容长度为0，因为这是一个空目录

        byte[] buffer = new byte[0]; // 创建一个空的字节数组作为输入流的内容
        ByteArrayInputStream in = new ByteArrayInputStream(buffer);  // 创建一个ByteArrayInputStream，内容为上面的空字节数组
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, targetFilePath, in);  // 将对象写入请求中

        try {
            // 上传对象到oss
            PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
            System.out.println(putObjectResult);
            return true;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                // 关闭OSSClient。
                ossClient.shutdown();
            }
        }
        return false;
    }

    /**
     * 上传QR二维码
     * @param file
     * @param userId
     * @return
     */
    public String uploadImg(File file, Long userId) {
        String bucketName = "network-disk-qr-1";
        if (!file.exists()) {
            return "";
        }
        String targetFilePath = userId + "/" + file.getName();
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, targetFilePath, file);
        try {
             ossClient.putObject(putObjectRequest);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                // 关闭OSSClient。
                ossClient.shutdown();
            }
        }
        return generateUrl(bucketName, targetFilePath, new Date(System.currentTimeMillis() + 3000L * 1000 * 24 * 10000));
    }

    /**
     * 上传用户头像
     * @param file
     * @param userId
     * @return
     * @throws IOException
     */
    public String   uploadAvatar(MultipartFile file, Long userId) throws IOException {
        String bucketName = "network-disk-avatar-1";   // 存储头像的bucket
        //生成了上传到 OSS的目标文件路径，路径包括了用户的唯一标识 userId 和上传文件的原始文件名
        String targetFilePath = userId + "/" + file.getOriginalFilename();
        //通过配置文件中的信息来创建连接OSS客户端的对象
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        //创建了包括要存储的 bucket 名称、对象的路径（或键）以及对象数据的输入流对象
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, targetFilePath, file.getInputStream());

        try {
            // 这行代码的意思是使用 ossClient 对象调用其 putObject 方法，
            // 将指定的对象（文件）上传到 OSS（阿里云对象存储）服务中。
            ossClient.putObject(putObjectRequest);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                // 关闭OSSClient。
                ossClient.shutdown();
            }
        }
        return generateUrl(bucketName, targetFilePath, new Date(System.currentTimeMillis() + 3000L * 1000 * 24 * 10000));
    }
    /**
     * 普通文件上传
     *
     * @param bucketName
     * @param targetFilePath
     * @param localFilePath
     * @return
     */
    public boolean normalUpload(String bucketName, String targetFilePath, String localFilePath) {
        File file = new File(localFilePath);
        if (!file.exists()) {
            return false;
        }
        targetFilePath = targetFilePath + "/" + localFilePath.substring(localFilePath.lastIndexOf(File.separator) + 1);
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, targetFilePath, file);

        try {
            ossClient.putObject(putObjectRequest);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        ossClient.shutdown();
        return true;
    }


    /**
     * 断点续传上传
     *
     * @return
     */
    public boolean resumeUpload(String bucketName, String localFilePath, String prefix) throws Throwable {
        File file = new File(localFilePath);


        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 不存在文件夹，新创建
        if (!file.exists() && !localFilePath.contains(".")) {
                localFilePath = prefix + localFilePath + "/";
            CompleteMultipartUploadResult uploadResult = doUploadRequest(localFilePath, bucketName, localFilePath, ossClient);
            log.info("上传" + localFilePath + "e-tag:" + uploadResult.getETag());
            return true;
        }
        if (file.isDirectory()) {
            // 存在本地文件夹，上传
            String dir =localFilePath.substring(localFilePath.lastIndexOf(File.separator) + 1);
            List<String> files = FileUtil.getDirFiles(file);
            assert files != null;
            for (String f : files) {
                String key = prefix + f.substring(f.lastIndexOf(dir));
                // windows分隔符转换
                key = key.replaceAll("\\\\", "/");
                // 文件夹
                if (!key.contains(".")) {
                    key += "/";
                }
                CompleteMultipartUploadResult uploadResult = doUploadRequest(f, bucketName, key, ossClient);
                log.info("上传" + localFilePath + "e-tag:" + uploadResult.getETag());

            }
        }
        ossClient.shutdown();
        return true;
    }

    private CompleteMultipartUploadResult doUploadRequest(String filePath, String bucketName, String key, OSS ossClient) throws Throwable {
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType("text/plain");
        UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);

        uploadFileRequest.setUploadFile(filePath);
        // 指定上传并发线程数，默认值为1。
        uploadFileRequest.setTaskNum(5);
        // 指定上传的分片大小。
        uploadFileRequest.setPartSize(1024 * 1024);
        // 开启断点续传，默认关闭。
        uploadFileRequest.setEnableCheckpoint(true);
        // 记录本地分片上传结果的文件。上传过程中的进度信息会保存在该文件中。
        //        uploadFileRequest.setCheckpointFile(localFil);
        // 文件的元数据。
        uploadFileRequest.setObjectMetadata(meta);
        UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);
        //        uploadFileRequest.setCallback();
        // 断点续传上传。
        CompleteMultipartUploadResult multipartUploadResult =
                uploadResult.getMultipartUploadResult();
        return multipartUploadResult;
    }



    // ****************下载文件************************

    /**
     * 普通下载
     *
     * @param localFilePath 下载到的本地位置
     * @param objectPath    oss文件路径
     */
    public boolean normalDownload(String bucketName, String localFilePath, String objectPath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.getObject(new GetObjectRequest(bucketName, objectPath)
                    , new File(localFilePath));
        } catch (Exception e) {
            // 下载失败！请稍后再试
            throw new DownloadException(MessageConstant.DOWNLOAD_FAILED);
        }
        ossClient.shutdown();
        return true;
    }

    /**
     * 断点续传下载
     *
     * @return
     */
    public boolean resumeDownload(String bucketName, String localFilePath, String objectPath) throws Throwable {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 下载请求，10个任务并发下载，启动断点续传。
        DownloadFileRequest downloadFileRequest = new DownloadFileRequest(bucketName, objectPath);
        downloadFileRequest.setDownloadFile(localFilePath);
        downloadFileRequest.setPartSize(1024 * 1024);
        downloadFileRequest.setTaskNum(10);
        downloadFileRequest.setEnableCheckpoint(true);
        downloadFileRequest.setCheckpointFile(localFilePath + ".dcp");

// 下载文件。
        DownloadFileResult downloadRes = null;
            downloadRes = ossClient.downloadFile(downloadFileRequest);

// 下载成功时，会返回文件元信息。
        ObjectMetadata objectMetadata = downloadRes.getObjectMetadata();
        System.out.println(objectMetadata.getETag());
        System.out.println(objectMetadata.getLastModified());
        System.out.println(objectMetadata.getUserMetadata().get("meta"));

        ossClient.shutdown();
        return true;
    }

    /**
     * 浏览器流式下载
     */
    public void streamDownload(String bucketName, String objectPath, HttpServletResponse response) {
        InputStream in = null;
        OutputStream out = null;
        try {
            response.reset();
            String fileName = objectPath.substring(objectPath.lastIndexOf('/') + 1);
            response.setContentType("application/x-download");
            response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
            out = response.getOutputStream();
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            OSSObject object = ossClient.getObject(bucketName, objectPath);
            log.info("正在下载"+ object);
            in = object.getObjectContent();
            byte[] data = new byte[1024];
            int len = 0;
            while ((len = in.read(data)) != -1) {
                out.write(data, 0, len);
            }
            out.flush();
            object.close();
            ossClient.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    // *************管理文件************

    /**
     *  分页列举所有文件
     * @param bucketName
     * @param maxKeys 每页最大个数
     * @return
     */
    public List<OSSObjectSummary> listFilesPaged(String bucketName,int currentPage, int maxKeys) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String nextContinuationToken = null;
        ListObjectsV2Result result = null;
        List<OSSObjectSummary> sums = null;
        // 分页列举，每次传入上次返回结果中的nextContinuationToken。
        do {
            ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName).withMaxKeys(maxKeys);
            listObjectsV2Request.setContinuationToken(nextContinuationToken);
            result = ossClient.listObjectsV2(listObjectsV2Request);

            sums = result.getObjectSummaries();

            nextContinuationToken = result.getNextContinuationToken();
            currentPage--;
        } while (result.isTruncated() && currentPage > 0);

// 关闭OSSClient。
        ossClient.shutdown();
        return sums;
    }

    public List<OSSObjectSummary> listFilesByPrefixPaged(String bucketName,int currentPage, int size, String prefix) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String nextContinuationToken = null;
        ListObjectsV2Result result = null;
        List<OSSObjectSummary> sums = null;
        // 分页列举指定前缀的文件。
        do {
            ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName).withMaxKeys(size);
            listObjectsV2Request.setPrefix(prefix);
            listObjectsV2Request.setContinuationToken(nextContinuationToken);
            result = ossClient.listObjectsV2(listObjectsV2Request);

            sums = result.getObjectSummaries();

            nextContinuationToken = result.getNextContinuationToken();
            currentPage--;
        } while (currentPage > 0 && result.isTruncated());

// 关闭OSSClient。
        ossClient.shutdown();
        return sums;
    }

    /**
     * 删除文件
     */
    public Boolean deleteFile(String bucketName,String filePath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 删除文件或目录。如果要删除目录，目录必须为空。
        try {
            ossClient.deleteObject(bucketName, filePath);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件删除失败!"+ e.getMessage());
        }
// 关闭OSSClient。
        ossClient.shutdown();
        return true;
    }

    /**
     * 删除文件夹及其下所有文件
     * @return
     */
    public Boolean deleteDir(String bucketName,String filePath) {
        // 填写不包含Bucket名称在内的目录完整路径。例如Bucket下testdir目录的完整路径为testdir/。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 删除目录及目录下的所有文件。
        String nextMarker = null;
        ObjectListing objectListing = null;
        do {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
                    .withPrefix(filePath)
                    .withMarker(nextMarker);

            objectListing = ossClient.listObjects(listObjectsRequest);
            if (!objectListing.getObjectSummaries().isEmpty()) {
                List<String> keys = new ArrayList<String>();
                for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
                    System.out.println("key name: " + s.getKey());
                    keys.add(s.getKey());
                }
                DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(keys);
                DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteObjectsRequest);
                List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();

            }

            nextMarker = objectListing.getNextMarker();
        } while (objectListing.isTruncated());

        ossClient.shutdown();
        return true;
    }


    /**
     * 获取文件oss路径
     * @param bucketName
     * @param ossPath
     * @return
     */
    public String generateUrl(String bucketName, String ossPath, Date expiration) {
        //创建连接OSS的对象
        OSS client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 生成签名URL。其封装了生成预签名URL所需的所有信息，包括存储桶名称、对象路径和访问方法。
        //持有该URL的用户可以直接通过浏览器或其他HTTP客户端访问指定的对象，
        // 而无需直接暴露 accessKeyId 和 accessKeySecret。保护服务器信息
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, ossPath, HttpMethod.GET);
        // 设置过期时间。
        request.setExpiration(expiration);
        // 生成了一个带有签名的URL
        URL signedUrl = client.generatePresignedUrl(request);
        // 打印签名URL。
        System.out.println("signed url for getObject: " + signedUrl);

        return signedUrl.toString();
    }

    public String copyObject(String bucketName,String sourcePath, String destPath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        CopyObjectResult result = ossClient.copyObject(bucketName, sourcePath, bucketName, destPath);
        System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());

// 关闭OSSClient。
        ossClient.shutdown();
        return result.getETag();
    }

    public SimplifiedObjectMeta getDetail(String bucketName, String ossPath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        return ossClient.getSimplifiedObjectMeta(bucketName, ossPath);
    }

    public boolean getFileExist(String bucketName, String ossPath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        boolean found = ossClient.doesObjectExist(bucketName, ossPath);
        ossClient.shutdown();
        return found;
    }

    /**
     * 单文件拷贝
     * @param srcBucket
     * @param srcPath
     * @param destBucket
     * @param destPath
     * @return
     */
    public boolean copySameRegionBucketFile(String srcBucket, String srcPath, String destBucket, String destPath) {
        if (!getFileExist(srcBucket, srcPath)) {
            throw new RuntimeException("文件不存在");
        }
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            CopyObjectResult result = ossClient.copyObject(srcBucket, srcPath, destBucket, destPath);
            System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
            throw new OSSException(MessageConstant.OSS_TRANSFER_FILE_FAULT);
        } finally {
            if (ossClient != null) {
                // 关闭OSSClient。
                ossClient.shutdown();
            }
        }
        return true;
    }


    /**
     * 获取根目录下所有文件大小
     * @param bucketName
     * @return
     */
    public Long getUserUsedSpace(String bucketName){
        try {
            //创建一个连接OSS对象
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            long sizeTotal = 0L;
            ObjectListing objectListing = null;
            do {
                // 每次列举1000个文件或目录。
                //能够按照层级结构列出存储桶中的对象（文件和目录），并且每次请求最多返回 1000 个对象。
                //随后，代码会使用这个请求对象与 OSS 交互，获取存储桶中的对象列表，并计算这些对象的总大小。
                ListObjectsRequest request = new ListObjectsRequest(bucketName).withDelimiter("/").withMaxKeys(1000);
                if (objectListing != null) {
                    //设置请求的分页标记 marker，使下一个请求从上次返回的最后一个对象开始。
                    request.setMarker(objectListing.getNextMarker());
                }
                //使用 ossClient 发送请求，获取对象列表，并将结果存储在 objectListing 中。
                objectListing = ossClient.listObjects(request);
                //获取当前目录下的所有子目录
                List<String> folders = objectListing.getCommonPrefixes();
                //调用 calculateFolderLength 方法计算每个子目录的大小，并累加到 sizeTotal。
                for (String folder : folders) {
                    sizeTotal = calculateFolderLength(ossClient, bucketName, folder)+sizeTotal;
                }
                //获取当前文件夹下所有文件大小
                List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
                if (sums.size()==0){
                    continue;
                }
                for (OSSObjectSummary s : sums) {
                    sizeTotal = sizeTotal+s.getSize();
                }

            } while (objectListing.isTruncated());
            //转换为TB
//            sizeTotal = sizeTotal/1024/1024/1024/1024;
            log.info(" 文件夹下所有子目录大小 : [{}] bytes",sizeTotal);
            //这行代码用于关闭 ossClient 对象
            ossClient.shutdown();
            return sizeTotal;
        }catch (Exception e){
            e.printStackTrace();
            return 0L;
        }

    }

    private static long calculateFolderLength(OSS ossClient, String bucketName, String folder) {
        long size = 0L;
        ObjectListing objectListing = null;
        do {
            // MaxKey默认值为100，最大值为1000。
            ListObjectsRequest request = new ListObjectsRequest(bucketName).withPrefix(folder).withMaxKeys(1000);
            if (objectListing != null) {
                request.setMarker(objectListing.getNextMarker());
            }
            objectListing = ossClient.listObjects(request);
            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
            for (OSSObjectSummary s : sums) {
                size += s.getSize();
            }
        } while (objectListing.isTruncated());
        return size;
    }

    /**
     * 重命名文件（单文件）
     * @param bucketName
     * @param oldFilePath
     * @param newFilePath
     */
    public void FileRename(String bucketName, String oldFilePath, String newFilePath) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.copyObject(bucketName, oldFilePath, bucketName, newFilePath);
            ossClient.deleteObject(bucketName, oldFilePath);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 重命名文件夹
     * @param bucketName
     * @param oldDirPath
     * @param newDirPath
     */
    public void DirRename(String bucketName, String oldDirPath, String newDirPath) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 列出源目录下的所有文件和子目录
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName).withPrefix(oldDirPath);
            ObjectListing objectListing;

            do {
                objectListing = ossClient.listObjects(listObjectsRequest);
                List<OSSObjectSummary> objectSummaries = objectListing.getObjectSummaries();
                for (OSSObjectSummary objectSummary : objectSummaries) {
                    String sourceKey = objectSummary.getKey();
                    // 计算目标Key
                    String destinationKey = newDirPath + sourceKey.substring(oldDirPath.length());

                    // 拷贝源文件到目标文件
                    ossClient.copyObject(bucketName, sourceKey, bucketName, destinationKey);

                    // 删除源文件
                    ossClient.deleteObject(bucketName, sourceKey);
                }
                listObjectsRequest.setMarker(objectListing.getNextMarker());
            } while (objectListing.isTruncated());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

}
